﻿using System.Text.RegularExpressions;

namespace zijian666.Data.SqlBuilders;
internal class MySqlBuilder : TSqlBuilder
{
    private static readonly Regex QUOTE_IDENTIFIER = new Regex(@"`(?<name>[^`]+)`", RegexOptions.Compiled);
    public static readonly MySqlBuilder Instance = new MySqlBuilder();
    public override string PagingSql(string sql, long begin, int count)
    {
        return $"{sql.TrimSemicolon()} LIMIT {count} OFFSET {begin}";
    }

    public override string ConvertCountSql(string sql)
    {
        var tokens = QUOTE_IDENTIFIER.Replace(sql, m => '[' + m.Groups["name"].Value + ']').ParseSqlTokens();
        if (tokens.Count is 0)
        {
            return $"SELECT COUNT(1) FROM ({sql.TrimSemicolon()}) AS T;";
        }

        var (begin1, end1) = tokens.GetTopSelectColumn();
        if (begin1 is null || end1 is null)
        {
            return $"SELECT COUNT(1) FROM ({sql.TrimSemicolon()}) AS T;";
        }

        var buffer = new StringBuilder(sql);

        var (begin2, end2) = tokens.GetTopOrderBy();
        if (begin2 is not null && end2 is not null)
        {
            buffer.Remove(begin2.Offset, end2.Offset - begin2.Offset);
        }


        buffer.Remove(begin1.Offset, end1.Offset - begin1.Offset);
        buffer.Insert(begin1.Offset, " COUNT(1) ");

        return buffer.ToString();
    }

    private DbProviderFactory _dbProvider = default!;

    public override DbProviderFactory DbProvider
    {
        get
        {
            if (_dbProvider is null)
            {
                if (DbProviderFactories.TryGetFactory("MySql.Data.MySqlClient", out _dbProvider!))
                {
                    return _dbProvider;
                }
                var name = DbProviderFactories.GetProviderInvariantNames().FirstOrDefault(x => x.Contains("MySql", StringComparison.OrdinalIgnoreCase));
                if (name is null)
                {
                    throw new NotSupportedException("未找到 MySql 提供程序");
                }
                _dbProvider = DbProviderFactories.GetFactory(name);
            }
            return _dbProvider;
        }
    }

    public override string GetParameterHolder(string parameterName)
    {
        return $"@{parameterName}";
    }
}
